#include<iostream>

using namespace std;

int fun1(int i);
int fun2(const int i);
int pfun1(int *pi);
int pfun2(const int *pi);
int pfun3(int *const pi);
int rfun1(int &r);
int rfun2(const int &r);

int main() {

    //num1为int类型的变量，可以修改它的值
    //num2为int类型的常量，不可以修改它的值
    int num1 = 10;
    const int num2 = 10;
    num1 = 20;
    //num2 = 20;

    //普通指针，可以修改p1的值，也以通过修改*p1来修改num1的值。
    //所以只能用int类型的数据来初始化，不能用const int类型，不能修改常量的值
    int *p1 = &num1;
    //int *p2 = &num2; //出错

    //底层const，可以修改指针（p3,p4），但是不可以通过*p3,*p4，去修改num1, num2的值。
    //可以使用int类型或const int类型的数据来初始化
    const int *p3 = &num1;
    const int *p4 = &num2;

    //顶层const，不可以修改指针（p5,p6），但是可以通过*p5去修改num1的值。
    //所以只能使用int类型的数据来初始化，不能const int类型
    int * const p5 = &num1;
    //int * const p6 = &num2;  //错误

    //int类型的引用，可以通过r1去修改num1的值，所以只能用int类型去初始化，不能使用const int类型
    int &r1 = num1;
    //int &r2 = num2; //出错

    //const int类型的引用，不能修改r3,r4的值
    //可以使用int类型的数据来初始化，也可以使用const int类型
    const int &r3 = num1;
    const int &r4 = num2;

    //实参为int类型或const int类型
    cout << fun1(num1)  << " "<< fun1(num2) << endl;
    cout << fun2(num1) << " " << fun2(num2) << endl;

    //实参只能为int类型
    cout << pfun1(&num1) << endl;
    //cout << pfun1(&num2) << endl; //出错

    //所以实参可以是int类型，也可以是const int类型
    cout << pfun2(&num1) << " " << pfun2(&num2) << endl;

    //所以实参类型只能是int类型
    cout << pfun3(&num1) << endl;
    //cout << pfun3(&num2) << endl; //出错

    //实参类型只能是int类型
    cout << rfun1(num1) << endl;
    //cout << rfun1(num2) << endl; //出错

    //实参类型可以是int类型，也可以是const int类型
    cout << rfun2(num1) << " " << rfun2(num2) << endl;
    return 0;
}

//可以修改形参i
int fun1(int i)
{
    //i = 0;
    return i * i * i;
}
//不可以修改形参i
int fun2(const int i)
{
    //i = 0;  //出错
    return i * i * i;
}

int pfun1(int *pi)
{
    //*pi = 0;
    return *pi * (*pi) *(*pi);
}

//可以修改pi，但是不可以修改*pi。所以实参可以是int类型，也可以是const int类型
int pfun2(const int *pi)
{
    //*pi = 0;  //出错
    return *pi * (*pi) *(*pi);
}

//不可以修改pi，但是可以修改*pi，所以实参类型只能是int类型
int pfun3(int *const pi)
{
    //*pi = 0;
    return *pi * (*pi) *(*pi);
}

//可以修改r，实参类型只能是int类型
int rfun1(int &r)
{
    //r = r * r * r;
    return r * r * r;
}
//不可以修改r,实参类型可以是int类型，也可以是const int类型
int rfun2(const int &r)
{
    //r = r * r * r; //出错
    return r * r * r;
}
